﻿#include"unrealircd.h"


/**
 * 为实现unrealIRCD的web服务器
 * 
 */


#define WBU(client)	(client->webUser)

const char http_methods[][10]={"GET","POST","DELETE","HEAD","PUT"};

URLFunc urlFuncArray[WEB_URL_MAXNUM];
int urlFuncArrayNum;


/**
 * 初始化url
 */
void urlFunc_init(){
	urlFuncArrayNum=0;
	urlFuncAdd("/api/test",testfunc,REQUEST_GET|REQUEST_POST);
}
void urlFuncAdd(char *url,url_callback func,int methods){
	int left=0;
	int right=urlFuncArrayNum-1;
	while(left<right){
		int mid=(left+right)>>1;
		int diff=strcmp(url,urlFuncArray[mid].url);
		if(diff==0){
			config_error("url is already exist");
			return;
		}
		else if(diff<0){
			right=mid-1;
		}
		else{
			left=mid+1;
		}
	}
	int diff=-1;
	if(urlFuncArray[left].url!=NULL){
		diff=strcmp(url,urlFuncArray[left].url);
	}
	if(diff==0){
		config_error("url is already exist");
	}
	else if(diff>0){
		left++;
	}
	for(int i=urlFuncArrayNum-1;i>=left;i--){
		urlFuncArray[i+1].url=urlFuncArray[i].url;
		urlFuncArray[i+1].func=urlFuncArray[i].func;
		urlFuncArray[i+1].method=urlFuncArray[i].method;
	}
	urlFuncArray[left].url=url;
	urlFuncArray[left].func=func;
	urlFuncArray[left].method=methods;
	urlFuncArrayNum++;
}


void WebServer_init(){
	urlFunc_init();
	llhttpSetting_init();
}

/**
 * 验证收到的信息为http协议
 */
int web_packet_in(Client *client, char *readbuf, int *length){
	ircd_log(LOG_ERROR,"web_packet_in :receiveM:%d,length:%d,isWBU:%d",client->local->receiveM,*length,(WBU(client)? 1: 0));
	if((client->local->receiveM == 0)&&!WBU(client)&&(*length > 8)&&IsHttpMethod(readbuf,length)){
		// ircd_log(LOG_ERROR,"recive http data :\n%s",readbuf);
		client->webUser=new_WebUser();
		list_move(&client->lclient_node, &unlogined_client_list);
		irccounts.unknown--;
		irccounts.webUser++;
	}
	if(!WBU(client)){
		return 1;
	}
	if(httpRequest_prase(client->webUser,readbuf,*length)){
		ircd_log(LOG_ERROR,"recive httpRequest_prase done ");
		http_proces(client);
		
	}
	//sendto_one(client, NULL, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 13\r\nConnection: close\r\n\r\n hello world!");
	
	return 0;
}

/**
 * 判断是否为http协议，目前只判断http方法，例如get，post等
 */
int IsHttpMethod(char *readbuf, int *length){
	int method_type_num=sizeof(http_methods)/sizeof(http_methods[1]);
	int isMethod=0;
	for(int i=0;i<method_type_num;++i){
		int method_len=strlen(http_methods[i]);
		if(!strncmp(readbuf, http_methods[i], method_len)&&!(*length<=method_len)&&readbuf[method_len]==' '){
			isMethod=1;
			return isMethod;
		}
	}
	return isMethod;
}


/**
 * 结束请求后释放数据
 */
void webUser_free(WebUser *webUser){
	if(webUser){
		ircd_log(LOG_ERROR,"begin webWuser free");
		web_requestData_free(webUser->requestData);
		ircd_log(LOG_ERROR,"begin response free");
		web_responseData_free(webUser->responseData);
		safe_free(webUser);
		ircd_log(LOG_ERROR,"end webWuser free");
		irccounts.webUser--;
	}
}
void httpHeader_free(HttpHeader *http_header){
	while(http_header){
		HttpHeader *temp=http_header->next;
		safe_free(http_header->head_field);
		safe_free(http_header->head_value);
		safe_free(http_header);
		http_header=temp;
	}
}
void urlParamList_free(UrlParamList *paramlist){
	while(paramlist){
		UrlParamList *temp=paramlist->next;
		safe_free(paramlist->param_name);
		safe_free(paramlist->param_value);
		safe_free(paramlist);
		paramlist=temp;
	}
}
void web_requestData_free(RequestData *requestData){
	safe_free(requestData->lefttoparse);
	safe_free(requestData->requestBody);
	safe_free(requestData->requestUrl);
	urlParamList_free(requestData->paramlist);
	httpHeader_free(requestData->requestHeader);
	safe_free(requestData);
}
void web_responseData_free(ResponseData *responseData){
	safe_free(responseData->lefttoparse);
	safe_free(responseData->responseBody);
	safe_free(responseData->responseReason);
	httpHeader_free(responseData->responseHeader);
	safe_free(responseData);
}
void requestData_add_header(RequestData *requestData,char *field,char *value){
	// ircd_log(LOG_ERROR,"requestData_add_header,head:%s,field:%s",value,field);
	HttpHeader *header=safe_alloc(sizeof(HttpHeader));
	header->head_field=NULL;
	header->head_value=NULL;
	safe_strdup(header->head_field, field);
	safe_strdup(header->head_value, value);
	header->pre=NULL;
	if(requestData->requestHeader){
		header->next=requestData->requestHeader;
		requestData->requestHeader->pre=header;
		requestData->requestHeader=header;
	}
	else{
		header->next=NULL;
		requestData->requestHeader=header;
	}
}

/**
 * 将url中的参数用从小到大的插入的RequestData的paramlist中
 */
void requestData_add_paramList(RequestData *requestData,char *field,char *value){
	UrlParamList *paramList=safe_alloc(sizeof(UrlParamList));
	paramList->param_name=field;
	paramList->param_value=value;
	if(requestData->paramlist){
		UrlParamList *nowList=requestData->paramlist;
		while(nowList){
			int diff=strcmp(nowList->param_name,paramList->param_name);
			if(diff<0){
				paramList->pre=nowList->pre;
				nowList->pre=paramList;
				if(paramList->pre){
					paramList->pre->next=paramList;
				}
				paramList->next=nowList;
				if(nowList==requestData->paramlist){
					requestData->paramlist=paramList;
				}
				break;
			}
			else if(diff==0){
				safe_strdup(nowList->param_value,value);
				urlParamList_free(paramList);
				break;
			}
			else if(nowList->next==NULL){
				paramList->next=NULL;
				nowList->next=paramList;
				paramList->pre=nowList;
				break;
			}
			else{
				nowList=nowList->next;
			}
		}
		
	}
	else{
		requestData->paramlist=paramList;
		paramList->pre=NULL;
		paramList->next=NULL;
	}
}
void responseData_add_header(ResponseData *responseData,char *field,char *value){
	HttpHeader *header=safe_alloc(sizeof(HttpHeader));
	header->head_field=NULL;
    header->head_value=NULL;
	safe_strdup(header->head_field,field);
	safe_strdup(header->head_value,value);
	HttpHeader *reheader;
	if(responseData->responseHeader){
		reheader=responseData->responseHeader;
		while(reheader){
			int diff=strcasecmp(reheader->head_field,header->head_field);
			if(diff==0){
				safe_strdup(reheader->head_value,value);
				safe_free(header->head_field);
				safe_free(header->head_value);
				safe_free(header);
				break;
			}
			else if(diff>0){
				if(reheader->pre){
					reheader->pre->next=header;
					header->pre=reheader->pre;
					header->next=reheader;
					reheader->pre=header;
				}
				else{
					reheader->pre=header;
					header->pre=NULL;
					header->next=reheader;
					responseData->responseHeader = header;
				}
				break;
			}
			if(!(reheader->next)){
				reheader->next=header;
				header->pre=reheader;
				header->next=NULL;
				break;
			}
			reheader=reheader->next;
		}
		
	}
	else{
		header->pre=NULL;
		header->next=NULL;
		responseData->responseHeader=header;
	}
	
}

/**
 * 创建一个WebUser数据，并将其初始化
 */
WebUser *new_WebUser(){
	WebUser *data=safe_alloc(sizeof(WebUser));
	data->requestData=new_RequestData();
	data->responseData=new_ResponseData();
	data->requestStatus=REQUESTSTATUS_REQUEST_UNFINISH;
	return data;
}

/**
 * 创建一个RequestData数据，并将其初始化
 */
RequestData *new_RequestData(){
	RequestData *data=safe_alloc(sizeof(RequestData));
	data->content_length=-1;
	data->lefttoparse=NULL;
	data->lefttoparselen=0;
	data->requestBody=NULL;
	data->requestBodyLength=0;
	data->requestHeader=NULL;
	data->requestUrl=NULL;
	data->trans_mode=TRANSMODE_NO;
	data->paramlist=NULL;
	return data;
}
/**
 * 创建一个ResponseData数据，并将其初始化
 */
ResponseData *new_ResponseData(){
	ResponseData *data=safe_alloc(sizeof(ResponseData));
	data->lefttoparselen=0;
	data->lefttoparse=NULL;
	data->responseBody=NULL;
	data->responseBodyLength=0;
	data->responseHeader=NULL;
	data->responseReason=NULL;
	data->responseStatus=0;
	return data;
}
/**
 * 处理http协议
 */
void http_proces(Client *client){
	WebUser *user=client->webUser;
	switch(user->requestStatus){
		case REQUESTSTATUS_REQUEST_PROCES:
			//执行url对应的方法
			{
				URLFunc *urlFunc=web_search_url(user->requestData->requestUrl,user->requestData->requestMethod);
				if(urlFunc){
					urlFunc->func(user);
					web_http_response_200(user);
				}
				else{//未找到路径，返回404
					web_http_response_404(user);
				}
			}
			break;
		case REQUESTSTATUS_REQUEST_SYNTAX_ERROR:
			web_http_response_400(user);
			break;
		case REQUESTSTATUS_UNKNOW_ERROR:
			web_http_response_500(user);
			break;
	}
	web_trans_response_data(client);
}
/**
 * 匹配URL
 */
URLFunc *web_search_url(char *url,int methods){
	int left=0;
	int right=urlFuncArrayNum-1;
	while(left<right){
		int mid=(left+right)>>1;
		int diff=strcmp(url,urlFuncArray[mid].url);
		if(diff==0){
			if(urlFuncArray[mid].method&methods){
				return &urlFuncArray[mid];
			}
			else{
				return NULL;
			}
		}
		else if(diff<0){
			right=mid-1;
		}
		else{
			left=mid+1;
		}
	}
	if(!strcmp(url,urlFuncArray[left].url)){
		if(urlFuncArray[left].method&methods){
			return &urlFuncArray[left];
		}
		else{
			return NULL;
		}
	}
	return NULL;
}

/**
 * 设置http响应的主体
 */
void web_set_httpResponseBody(WebUser *web_user,char *body){
	if(body){
		safe_strdup(web_user->responseData->responseBody,body);
		web_user->responseData->responseBodyLength=strlen(web_user->responseData->responseBody);
	}
	else{
		web_user->responseData->responseBodyLength=0;
	}
}

/**
 * 开始返回响应数据
 */
void web_trans_response_data(Client *client){
	WebUser *web_user=client->webUser;
	if(web_user->requestStatus!=REQUESTSTATUS_RESPONSE_TRANSFER){
		return;
	}
	char *response=web_make_response_string(web_user);
	dbuf_put(&client->local->sendQ, response, strlen(response));
	send_queued(client);
	safe_free(response);
	web_user->requestStatus=REQUESTSTATUS_READY_CLOSE;
	//dead_socket(client,"");
	close_connection(client);
}
/**
 * 构造response数据
 */
char * web_make_response_string(WebUser *web_user){
	char *header_string=web_make_response_header_string(web_user);
	char *response=safe_alloc(sizeof(char)*(WEB_RESPONSE_HEADER_MAX_LENGTH+web_user->responseData->responseBodyLength+strlen(header_string)));
	response[0]='\0';
	sprintf(response,"HTTP/1.1 %d %s\r\n%s\r\n%s",
		web_user->responseData->responseStatus,
		web_user->responseData->responseReason,
		header_string,
		web_user->responseData->responseBody
	);
	safe_free(header_string);
	return response;
}
/**
 * 将响应的头部构造成一个字符串
 */
char * web_make_response_header_string(WebUser *web_user){
	char *header=safe_alloc(sizeof(char)*(WEB_RESPONSE_HEADER_MAX_LENGTH));
	header[0]='\0';
	int header_size=WEB_RESPONSE_HEADER_MAX_LENGTH;
	int header_length=0;
	HttpHeader *httpHeader=web_user->responseData->responseHeader;
	while(httpHeader){
		char temp[1024]="";
		sprintf(temp,"%s: %s\r\n",httpHeader->head_field,httpHeader->head_value);
		int len=strlen(temp);
		if(header_length+len+1>header_size){
			char *header_temp=safe_alloc((header_length+len+1)<<1);
			header_size = (header_length+len+1)<<1;
			header_temp[0]='\0';
			strcat(header_temp,header);
			safe_free(header);
			header=header_temp;
		}
		strcat(header,temp);
		header_length = header_length + len;
		httpHeader=httpHeader->next;
	}
	return header;
}

/**
 * 查询是否存在一个param在请求的paramList中
 */
UrlParamList * web_request_get_paramList(RequestData *requestData,char *paramName){
	UrlParamList *temp=requestData->paramlist;
	while(temp){
		int diff=strcmp(paramName,temp->param_name);
		if(diff==0){
			break;
		}
		else if(diff>0){
			temp=NULL;
			break;
			
		}
		temp=temp->next;
	}
	return temp;
}

















/**
 * /api/test 路径的执行函数
 */
WEBFUNC(testfunc){
	cJSON * root = cJSON_CreateObject();
	cJSON_AddStringToObject(root, "message", "OK");
	cJSON_AddNumberToObject(root, "status", 1);
	cJSON_AddStringToObject(root, "url",web_user->requestData->requestUrl);
	cJSON_AddNumberToObject(root, "method",web_user->requestData->requestMethod);
	if(web_user->requestData->requestBody){
		cJSON_AddStringToObject(root, "data",web_user->requestData->requestBody);
	}
	else{
		cJSON_AddNullToObject(root, "data");
	}
	cJSON  *paramlistArry=cJSON_CreateArray();
	UrlParamList *paramlist=web_user->requestData->paramlist;
	while(paramlist){
		cJSON *paramNode=cJSON_CreateObject();
		cJSON_AddStringToObject(paramNode, "param_name", paramlist->param_name);
		cJSON_AddStringToObject(paramNode, "param_value", paramlist->param_value);
		cJSON_AddItemToArray(paramlistArry,paramNode);
		paramlist=paramlist->next;
	}
	cJSON_AddItemToObject(root, "paramlist",paramlistArry);

	cJSON  *headerlistArry=cJSON_CreateArray();
	HttpHeader *headerList=web_user->requestData->requestHeader;
	while(headerList){
		cJSON *headerNode=cJSON_CreateObject();
		cJSON_AddStringToObject(headerNode, "head_field", headerList->head_field);
		cJSON_AddStringToObject(headerNode, "head_value", headerList->head_value);
		cJSON_AddItemToArray(headerlistArry,headerNode);
		headerList=headerList->next;
	}
	cJSON_AddItemToObject(root, "headerlist",headerlistArry);

	web_set_httpResponseBody(web_user,cJSON_PrintUnformatted(root));
	cJSON_Delete(root);
}